package com.bloom.product.qms.event;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bloom.cloud.common.service.IMetaService;
import com.bloom.cloud.core.db.DynamicDataSourceHolder;
import com.bloom.cloud.core.entity.MailEntity;
import com.bloom.cloud.core.utils.DateUtils;
import com.bloom.cloud.processor.common.annotation.Executor;
import com.bloom.cloud.processor.common.annotation.ServiceExecutor;
import com.bloom.cloud.processor.common.model.TableColumnProps;
import com.bloom.cloud.processor.common.params.ServiceDefinitionParam;
import com.bloom.cloud.processor.common.params.ServiceInParam;
import com.bloom.cloud.processor.common.params.ServiceOutParam;
import com.bloom.cloud.processor.common.service.DynamicBaseExecutor;
import com.bloom.cloud.processor.main.utils.MailUtils;
import com.bloom.cloud.processor.utils.ParamUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;

import java.util.*;

/**
 * 流程预警
 * Created by ZLM
 */
@ServiceExecutor(code = "QMS_DYNAMIC_DELAY_WARING")
public class QMSDynamicDelayWaringExecutor extends DynamicBaseExecutor {

    @Autowired
    private IMetaService iMetaService;

    @Executor
    public ServiceOutParam execute(ServiceDefinitionParam param) {
        ServiceInParam inParam = param.getInParam();
        String system = param.getInParam().getInstance();
        List<Map<String, Object>> waringConfList = getWaringConf(system);
        if(waringConfList.size()>0){
            Map<String,Map<String,Object>> problemProcessMap = getProblemProcessInfo(system);
            Map<String,Map<String,Object>> userMap = getUserInfo(system);
            Map<String,Map<String,Object>> warnLogMap = getWarnLogInfo(system);
            List<Map<String,Object>> delayWaringLogList = new ArrayList<>();

            HashMap<String,List<String>> emailUserMaps = new HashMap<>(); //  邮箱KEY =》 通知用户
            HashMap<String, HashMap<String,Object>> emailInfoMaps = new HashMap<>();
            for (Map<String, Object> waringConfMap : waringConfList){
                String procDefName = waringConfMap.get("PROC_DEF_NAME").toString();
                String procDefKey = waringConfMap.get("PROC_DEF_KEY").toString();
                String startNodeKey = waringConfMap.get("START_NODE_KEY").toString();
                String endNodeKey = waringConfMap.get("END_NODE_KEY").toString();
                String startNodeName = waringConfMap.get("START_NODE_NAME").toString();
                String endNodeName = waringConfMap.get("END_NODE_NAME").toString();
                Integer delayDays = Integer.parseInt(waringConfMap.get("DELAY_DAYS").toString());// 逾期天数
                String title = waringConfMap.get("CODE").toString();// 标题
                Integer delayId = Integer.parseInt(waringConfMap.get("ID").toString());
                Integer baseId = waringConfMap.get("BASE_ID") != null ? Integer.parseInt(waringConfMap.get("BASE_ID").toString()) : null;

                Map<String,Object> rtnMap = new HashMap<>();
                Map<String,String> assigneeMap = new HashMap<>();
                HashMap<String,HashMap<String,Date>> nodeMap = new HashMap<>();
                /**
                 * 1.排查符合基本流程信息数据
                 *   流程KEY  流程名称  超期开始节点KEY  超期结束节点KEY    DELAY_DAYS-逾期天数；DELAY_TO_DATE-特定日期
                 *   返回 需要预警 的 具体 流程
                 */
                rtnMap = getNodeStartEndTime(procDefKey,startNodeKey,endNodeKey,system);
                nodeMap = (HashMap<String,HashMap<String,Date>>)rtnMap.get("procMap");
                assigneeMap = (Map<String,String>)rtnMap.get("assigneeMap");

                for (String businessId : nodeMap.keySet()) {
                    HashMap<String,Date> dateMap = nodeMap.get(businessId);
                    Map<String,Object> problemProcessData = problemProcessMap.get(businessId);
                    if(problemProcessData == null){
                        continue;
                    }else{
                        String processStatus = String.valueOf(problemProcessData.get("PROCESS_STATUS"));
                        if("END".equals(processStatus) || "CLOSE".equals(processStatus) || "CLOSE_BY_PROBLEM_UPGRADE".equals(processStatus) || "CLOSE_BY_PROCESS_UPGRADE".equals(processStatus) || "CLOSE_BY_RECALL".equals(processStatus)){
                            continue;
                        }
                    }

                    if("FAST_REVERSAL_FLOW".equals(procDefKey) || "HIERARCHICAL_AUDIT_FLOW".equals(procDefKey)){
                        Map<String,Object> userData = userMap.get(problemProcessData.get("LAUNCH_PERSON_ACCOUNT").toString());
                        if(userData == null){
                            continue;
                        }
                        if(!(userData.get("BASE_ID") != null && baseId != null && baseId.toString().equals(userData.get("BASE_ID").toString()))){
                            continue;
                        }
                    }
                    Integer day = 0;
                    if(startNodeKey.equals(endNodeKey)){
                        Date startDate = (Date)dateMap.get("startTime");
                        Date endDate = (Date)dateMap.get("endTime");
                        day = DateUtils.getWorkDay(startDate,endDate);
                    }else{
                        Date startDate = (Date)dateMap.get(startNodeKey);
                        Date endDate = (Date)dateMap.get(endNodeKey);
                        day = DateUtils.getWorkDay(startDate,endDate);
                    }
                    Integer level = day/delayDays;
                    if(1 <= level && level <= 5){ // 逾期天数  大于5级就不通知了   浪费资源
                        if(! warnLogMap.containsKey(delayId + "_" + businessId + "_"+level)){
                            Map<String,Object> delayWarrMap = new HashMap<>();

                            // 当前办理人账号
                            String assigneeAccount = assigneeMap.get(businessId);
                            Map<String,Object> assigneeData = userMap.get(assigneeAccount);
                            if(assigneeData == null){
                                continue;
                            }

                            Map<String,Object> noticeData = null;

                            if("SUP".equals(assigneeData.get("USER_TYPE"))){

                            }else{
                                noticeData = getLeaderDataByAssigneeAndLevel(system,assigneeAccount,level);
                            }

                            // if(noticeData == null){
                            //     continue;
                            // }


                            delayWarrMap.put("title",title);
                            delayWarrMap.put("level",level);
                            delayWarrMap.put("delay_days",delayDays);
                            delayWarrMap.put("delay_id",delayId);
                            delayWarrMap.put("base_id",baseId);
                            delayWarrMap.put("problem_id",problemProcessData.get("PROBLEM_ID"));
                            delayWarrMap.put("problem_process_id",businessId);
                            delayWarrMap.put("problem_type",problemProcessData.get("PROBLEM_TYPE"));
                            delayWarrMap.put("process_type",problemProcessData.get("PROCESS_TYPE"));
                            delayWarrMap.put("process_status",problemProcessData.get("PROCESS_STATUS"));
                            delayWarrMap.put("problem_code",problemProcessData.get("PROBLEM_CODE"));
                            delayWarrMap.put("problem_desc",problemProcessData.get("PROBLEM_TITLE"));
                            delayWarrMap.put("process_instance_id",problemProcessData.get("PROCESS_INSTANCE_ID"));

                            delayWarrMap.put("task_user_name",assigneeData.get("USER_NAME"));
                            delayWarrMap.put("task_user_email",assigneeData.get("EMAIL"));
                            delayWarrMap.put("notice_user_name",noticeData != null ? noticeData.get("USER_NAME") : "");
                            delayWarrMap.put("notice_user_email",noticeData != null ? noticeData.get("EMAIL") : "");
                            delayWarrMap.put("remark",noticeData != null ? noticeData.get("RANK_LEVEL") : "");

                            delayWarrMap.put("start_node_key",startNodeKey);
                            delayWarrMap.put("end_node_key",endNodeKey);
                            delayWarrMap.put("start_node_name",startNodeName);
                            delayWarrMap.put("end_node_name",endNodeName);
                            delayWarrMap.put("detained_days",day);  // 滞留天数
                            delayWaringLogList.add(delayWarrMap);



                            List<String> userEmailList = new ArrayList<>();
                            if(noticeData != null && !"GM".equals(noticeData.get("RANK_LEVEL"))){
                                userEmailList.add(String.valueOf(noticeData.get("EMAIL")));
                            }
                            userEmailList.add(String.valueOf(assigneeData.get("EMAIL")));
                            emailUserMaps.put(businessId,userEmailList);

                            HashMap<String,Object> publicEmailInfo = new HashMap<>();
                            publicEmailInfo.put("procName",procDefName);
                            publicEmailInfo.put("startNodeName",startNodeName);
                            publicEmailInfo.put("endNodeName",endNodeName);
                            publicEmailInfo.put("problemCode",problemProcessData.get("PROBLEM_CODE"));

                            emailInfoMaps.put(businessId,publicEmailInfo);


                        }
                    }
                }
            }


            // 保存预警记录
            if(delayWaringLogList.size()>0){
                DynamicDataSourceHolder.setDbType(system);
                TableColumnProps tableColumnProps = param.getProps();
                delayWaringLogList.stream().forEach(item ->{
                    dynamicDataExecutor.save(item,param.getDefinition(),tableColumnProps);
                });
            }

            /**
             * 4.发送邮件提醒
             */
            if(emailUserMaps.size()>0){
                sendDelayWaringEmail(emailUserMaps,emailInfoMaps,inParam);
            }
        }
        HashMap<String, Object> map = new HashMap<>();
        map.put("data", "1112635482测试返回数据");
        return ServiceOutParam.success(map);
    }

    private Map<String,Object> getLeaderDataByAssigneeAndLevel(String system,String assignee,Integer level){
        DynamicDataSourceHolder.setDbType(system+"_admin");
        String organizationID = "";
        List<Map<String, Object>> assigneeInfoList = dynamicDataExecutor.findAllSql(new StringBuffer("select * from ts_user where  account = '" +assignee +"'"));
        if(assigneeInfoList != null && assigneeInfoList.size() > 0){
            organizationID = String.valueOf(assigneeInfoList.get(0).get("ORGANIZATION_ID"));
        }else{
            return null;
        }
        // leader 部门分管副总
        // senior_director 高级总监
        // director 总监
        // senior_manager 高级经理
        // manager 经理

        String leader = "a.leader";
        if (level == 1) {
            leader = "a.manager";
        }else if (level == 2) {
            leader = "a.seniormanager";
        }else if (level == 3) {
            leader = "a.director";
        }else if (level == 4) {
            leader = "a.seniordirector";
        }

        StringBuffer sql = new StringBuffer();
        sql.append(" SELECT b.* FROM ts_organization a LEFT JOIN ts_user b ON  FIND_IN_SET(b.ACCOUNT,"+leader+")  WHERE  a.id = " + organizationID);

        List<Map<String, Object>> userInfoList = dynamicDataExecutor.findAllSql(sql);
        DynamicDataSourceHolder.clearDBType();
        if(userInfoList != null && userInfoList.size() > 0){
            return userInfoList.get(0);
        }else{
            return null;
        }
    }

    /**
     * 查询问题关联流程基本信息
     * @return
     */
    private Map<String,Map<String,Object>> getProblemProcessInfo(String system){
        DynamicDataSourceHolder.setDbType(system);
        StringBuffer sql = new StringBuffer();
        sql.append("  select ID,PROCESS_INSTANCE_ID,PROBLEM_ID,PROBLEM_CODE,PROBLEM_TYPE,PROCESS_TYPE,PROBLEM_TITLE,LAUNCH_PERSON_ID,LAUNCH_PERSON_ACCOUNT,PROCESS_STATUS from tb_problem_process where mark_for_delete = 0 ");
        List<Map<String, Object>> problemInfoList = dynamicDataExecutor.findAllSql(sql);
        DynamicDataSourceHolder.clearDBType();
        Map<String,Map<String,Object>> rtnMap = new HashMap<>();
        if(problemInfoList != null && problemInfoList.size() > 0){
            for(Map<String, Object> map : problemInfoList){
                rtnMap.put(map.get("ID")+"",map);
            }
        }
        return rtnMap;
    }

    /**
     * 查询用户基本信息
     * @return
     */
    private Map<String,Map<String,Object>> getUserInfo(String system){
        DynamicDataSourceHolder.setDbType(system+"_admin");
        StringBuffer sql = new StringBuffer();
        sql.append(" select * from ts_user where  MARK_FOR_DELETE = 0 and `STATUS` = 'NORMAL'  ");
        List<Map<String, Object>> userInfoList = dynamicDataExecutor.findAllSql(sql);
        DynamicDataSourceHolder.clearDBType();
        Map<String,Map<String,Object>> rtnMap = new HashMap<>();
        if(userInfoList != null && userInfoList.size() > 0){
            for(Map<String, Object> map : userInfoList){
                rtnMap.put(map.get("ACCOUNT")+"",map);
            }
        }
        return rtnMap;
    }

    /**
     * 查询预警记录基本信息
     * @return
     */
    private Map<String,Map<String,Object>> getWarnLogInfo(String system){
        DynamicDataSourceHolder.setDbType(system);
        StringBuffer sql = new StringBuffer();
        sql.append(" select * from TB_DELAY_WARING_LOG where  MARK_FOR_DELETE = 0  ");
        List<Map<String, Object>> userInfoList = dynamicDataExecutor.findAllSql(sql);
        DynamicDataSourceHolder.clearDBType();
        Map<String,Map<String,Object>> rtnMap = new HashMap<>();
        if(userInfoList != null && userInfoList.size() > 0){
            for(Map<String, Object> map : userInfoList){
                rtnMap.put(map.get("DELAY_ID") + "_" + map.get("PROBLEM_PROCESS_ID") + "_" + map.get("LEVEL"),map);
            }
        }
        return rtnMap;
    }

    /**
     * 流程预警配置
     * @return
     */
    private List<Map<String, Object>> getWaringConf(String system){
        DynamicDataSourceHolder.setDbType(system+"_admin");
        StringBuffer sql = new StringBuffer();
        sql.append(" select ID,DEPLOYMENT_ID,PROC_DEF_KEY,PROC_DEF_NAME,START_NODE_KEY,END_NODE_KEY,START_NODE_NAME,END_NODE_NAME,DELAY_DAYS,CODE,BASE_ID from act_ws_delay_waring_conf  ");
        List<Map<String, Object>> waringConfList = dynamicDataExecutor.findAllSql(sql);
        DynamicDataSourceHolder.clearDBType();
        return waringConfList;
    }


    private List<Map<String, Object>> getWaringNodeSql(String procDefKey, String startNodeKey, String endNodeKey,String system){
        StringBuffer sql = new StringBuffer();
        DynamicDataSourceHolder.setDbType(system+"_admin");
        sql.append("      select ht.ID_ as 'taskId', ht.PROC_INST_ID_, hp.BUSINESS_KEY_,hp.PROC_DEF_KEY_,ht.TASK_DEF_KEY_,ht.NAME_,IFNULL(ru.ASSIGNEE_,ht.ASSIGNEE_) as ASSIGNEE,   ");
        sql.append("       ht.START_TIME_,ht.END_TIME_,ht.DELETE_REASON_ from act_hi_taskinst ht    ");
        sql.append("         LEFT JOIN act_hi_procinst hp on ht.PROC_INST_ID_ =  hp.PROC_INST_ID_   ");
        sql.append("         LEFT JOIN act_ru_task ru on ht.PROC_INST_ID_ =  ru.PROC_INST_ID_   ");
        sql.append("          where hp.STATE_ !='COMPLETED'  and ht.PROC_DEF_KEY_='"+procDefKey+"'  ");
        sql.append(" and ( ht.TASK_DEF_KEY_ = '"+startNodeKey+"' or ( ht.TASK_DEF_KEY_ = '"+endNodeKey+"' and ht.END_TIME_ is null  ))   ");
        sql.append("  ORDER BY ht.PROC_INST_ID_,ht.START_TIME_   ");
        List<Map<String, Object>> waringConfList = dynamicDataExecutor.findAllSql(sql);
        DynamicDataSourceHolder.clearDBType();
        return waringConfList;
    }

    private Map<String,Object> getNodeStartEndTime(String procDefKey, String startNodeKey, String endNodeKey,String system){
        Map<String,Object> rtnMap = new HashMap<>();
        HashMap<String,HashMap<String,Date>> procMap = new HashMap<>();
        Map<String,String> assigneeMap = new HashMap<>();
        List<Map<String,Object>> nodeMapInfoList = getWaringNodeSql(procDefKey, startNodeKey, endNodeKey,system);

        for(Map nodeMap : nodeMapInfoList){
            // 添加空值检查
            Object businessKey = nodeMap.get("BUSINESS_KEY_");
            if(businessKey == null) {
                continue; // 跳过无效记录
            }
            String key = businessKey.toString();

            Object taskDefKey = nodeMap.get("TASK_DEF_KEY_");
            if(taskDefKey == null) {
                continue; // 跳过无效记录
            }
            String node = taskDefKey.toString();

            Object assigneeObj = nodeMap.get("ASSIGNEE");
            String assignee = assigneeObj != null ? assigneeObj.toString() : "";

            assigneeMap.put(key, assignee);
            HashMap<String,Date> map = new HashMap<>();
            if(procMap.containsKey(key)){ // 已存在流程
                map = procMap.get(key);
            }
            if(startNodeKey.equals(node)){
                Object startTime = nodeMap.get("START_TIME_");
                Date startDate = convertToDate(startTime);
                map.put(node, startDate);
                map.put("startTime", startDate);
            }else if(endNodeKey.equals(node)){
                Object endTime = nodeMap.containsKey("END_TIME_") ? nodeMap.get("END_TIME_") : new Date();
                map.put(node, convertToDate(endTime));
            }
            if(endNodeKey.equals(node)){
                Object endTime = nodeMap.containsKey("END_TIME_") ? nodeMap.get("END_TIME_") : new Date();
                map.put("endTime", convertToDate(endTime));
            }
            if(!map.containsKey(startNodeKey)){
                map.put(startNodeKey,new Date());
            }
            if(!map.containsKey(endNodeKey)){
                map.put(endNodeKey,new Date());
            }
            procMap.put(key,map);
        }


        rtnMap.put("procMap",procMap);
        rtnMap.put("assigneeMap",assigneeMap);
        return rtnMap;
    }

    /**
     * 将时间对象转换为Date类型
     * @param timeObj 时间对象，可能是Date或LocalDateTime
     * @return 转换后的Date对象
     */
    private Date convertToDate(Object timeObj) {
        if (timeObj instanceof Date) {
            return (Date) timeObj;
        } else if (timeObj instanceof java.time.LocalDateTime) {
            return java.sql.Timestamp.valueOf((java.time.LocalDateTime) timeObj);
        }
        return new Date();
    }


    /**
     * 发送邮件
     * @param emailUserMaps
     * @param emailInfoMaps
     */
    private void sendDelayWaringEmail(HashMap<String, List<String>> emailUserMaps, HashMap<String, HashMap<String, Object>> emailInfoMaps,ServiceInParam inParam) {
        ServiceInParam serviceInParam = ServiceInParam.slot(inParam);
        serviceInParam.setFunctionCode("QMS_RABBITMQ_SEND_EMAIL");

        for(String key :  emailUserMaps.keySet()){
            List<String> strings = emailUserMaps.get(key);
            if (strings == null || strings.isEmpty()) {
                continue;
            }
            HashMap<String, Object> stringObjectHashMap = emailInfoMaps.get(key);
            if (stringObjectHashMap == null || stringObjectHashMap.isEmpty()) {
                continue;
            }
            
            Map<String, Object> params = new HashMap<>();
            params.put("subject", "8D流程超时预警提醒");
            params.put("mail_to", String.join(",", strings));
            params.put("content","【"+stringObjectHashMap.get("problemCode")+"】"+stringObjectHashMap.get("procName")+"流程,"+stringObjectHashMap.get("startNodeName")+"节点到"+stringObjectHashMap.get("endNodeName")+"节点超时，请及时处理！");

            serviceInParam.setParams(params);
            super.metaService.disposeService(JSON.toJSONString(serviceInParam));

        }
    }
}



